#####################################################
# Protobuf.cmake - Protobuf 集成模块
# 
# 提供protobuf的查找、配置和代码生成功能
# 自动处理proto文件编译和目标依赖关系
#####################################################

# 选项：是否启用protobuf支持
option(ENABLE_PROTOBUF "启用Protobuf支持" ON)

# 全局变量
set(PROTOBUF_ENABLED FALSE CACHE INTERNAL "Protobuf是否可用")
set(PROTOBUF_GENERATED_TARGET "" CACHE INTERNAL "Protobuf生成文件目标")
set(PROTOBUF_GENERATED_SRCS "" CACHE INTERNAL "Protobuf生成的源文件列表")
set(PROTOBUF_GENERATED_HDRS "" CACHE INTERNAL "Protobuf生成的头文件列表")

#####################################################
# 设置protobuf集成
# 查找protobuf库，配置编译环境
#####################################################
function(setup_protobuf)
    if(NOT ENABLE_PROTOBUF)
        message(STATUS "Protobuf: 已通过 ENABLE_PROTOBUF=OFF 禁用")
        return()
    endif()

    # 尝试查找protobuf
    find_package(Protobuf QUIET)
    
    if(Protobuf_FOUND)
        message(STATUS "Protobuf: 已找到系统安装的protobuf")
        message(STATUS "  版本: ${Protobuf_VERSION}")
        message(STATUS "  包含目录: ${Protobuf_INCLUDE_DIRS}")
        message(STATUS "  库文件: ${Protobuf_LIBRARIES}")
        message(STATUS "  编译器: ${Protobuf_PROTOC_EXECUTABLE}")
        
        # 设置到全局作用域
        set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIRS} CACHE INTERNAL "Protobuf包含目录")
        set(Protobuf_LIBRARIES ${Protobuf_LIBRARIES} CACHE INTERNAL "Protobuf库文件")
        set(Protobuf_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE} CACHE INTERNAL "Protobuf编译器")
        
        set(PROTOBUF_ENABLED TRUE CACHE INTERNAL "Protobuf是否可用")
        
    else()
        # 尝试从third_party子项目查找
        if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/CMakeLists.txt")
            message(STATUS "Protobuf: 使用third_party/protobuf子项目")
            add_subdirectory(third_party/protobuf)
            
            # 检查子项目是否成功创建了目标
            if(TARGET protobuf::libprotobuf)
                set(PROTOBUF_ENABLED TRUE CACHE INTERNAL "Protobuf是否可用")
                
                # 设置变量以兼容find_package结果
                get_target_property(Protobuf_INCLUDE_DIRS protobuf::libprotobuf INTERFACE_INCLUDE_DIRECTORIES)
                set(Protobuf_LIBRARIES protobuf::libprotobuf)
                
                # 查找protoc可执行文件
                find_program(Protobuf_PROTOC_EXECUTABLE protoc
                    PATHS ${CMAKE_CURRENT_SOURCE_DIR}/third_party/protobuf/bin
                    NO_DEFAULT_PATH
                )
                if(NOT Protobuf_PROTOC_EXECUTABLE)
                    find_program(Protobuf_PROTOC_EXECUTABLE protoc)
                endif()
                
                # 设置到全局作用域
                set(Protobuf_INCLUDE_DIRS ${Protobuf_INCLUDE_DIRS} CACHE INTERNAL "Protobuf包含目录")
                set(Protobuf_LIBRARIES ${Protobuf_LIBRARIES} CACHE INTERNAL "Protobuf库文件")
                set(Protobuf_PROTOC_EXECUTABLE ${Protobuf_PROTOC_EXECUTABLE} CACHE INTERNAL "Protobuf编译器")
                
                message(STATUS "  编译器: ${Protobuf_PROTOC_EXECUTABLE}")
            else()
                message(WARNING "Protobuf: third_party/protobuf子项目未能创建protobuf::libprotobuf目标")
            endif()
        else()
            message(STATUS "Protobuf: 未找到protobuf库，protobuf功能将被禁用")
        endif()
    endif()
    
    if(PROTOBUF_ENABLED)
        message(STATUS "Protobuf: 已启用protobuf支持")
    else()
        message(STATUS "Protobuf: protobuf支持已禁用")
    endif()
endfunction()

#####################################################
# 生成protobuf文件
# 查找所有proto文件并生成对应的C++代码
#####################################################
function(generate_protobuf_files)
    if(NOT PROTOBUF_ENABLED)
        return()
    endif()
    
    if(NOT Protobuf_PROTOC_EXECUTABLE)
        message(FATAL_ERROR "Protobuf: 未找到protoc编译器")
        return()
    endif()

    message(STATUS "Protobuf: 开始生成protobuf文件")
    
    # 查找所有proto文件
    file(GLOB_RECURSE PROTO_FILES "${CMAKE_CURRENT_SOURCE_DIR}/proto/*.proto")
    
    if(NOT PROTO_FILES)
        message(STATUS "Protobuf: 未找到proto文件")
        return()
    endif()
    
    message(STATUS "Protobuf: 找到 ${CMAKE_CURRENT_LIST_LENGTH} 个proto文件: ${PROTO_FILES}")
    
    # 生成protobuf文件
    set(GENERATED_SRCS)
    set(GENERATED_HDRS)
    
    foreach(PROTO_FILE ${PROTO_FILES})
        get_filename_component(PROTO_NAME ${PROTO_FILE} NAME_WE)
        get_filename_component(PROTO_DIR ${PROTO_FILE} DIRECTORY)
        
        set(GENERATED_SRC "${CMAKE_CURRENT_BINARY_DIR}/${PROTO_NAME}.pb.cc")
        set(GENERATED_HDR "${CMAKE_CURRENT_BINARY_DIR}/${PROTO_NAME}.pb.h")
        
        list(APPEND GENERATED_SRCS ${GENERATED_SRC})
        list(APPEND GENERATED_HDRS ${GENERATED_HDR})
        
        add_custom_command(
            OUTPUT ${GENERATED_SRC} ${GENERATED_HDR}
            COMMAND ${Protobuf_PROTOC_EXECUTABLE} 
                --cpp_out=${CMAKE_CURRENT_BINARY_DIR}
                --proto_path=${PROTO_DIR}
                ${PROTO_FILE}
            DEPENDS ${PROTO_FILE}
            COMMENT "Protobuf: 正在生成 ${PROTO_NAME}.pb.cc 和 ${PROTO_NAME}.pb.h"
            VERBATIM
        )
        
        message(STATUS "Protobuf: 将生成 ${PROTO_NAME}.pb.cc 和 ${PROTO_NAME}.pb.h")
    endforeach()
    
    # 创建包含所有生成文件的目标
    add_custom_target(proto_generated 
        DEPENDS ${GENERATED_SRCS} ${GENERATED_HDRS}
        COMMENT "Protobuf: 生成所有protobuf文件"
    )
    
    # 设置全局变量
    set(PROTOBUF_GENERATED_TARGET proto_generated CACHE INTERNAL "Protobuf生成文件目标")
    set(PROTOBUF_GENERATED_SRCS ${GENERATED_SRCS} CACHE INTERNAL "Protobuf生成的源文件列表")
    set(PROTOBUF_GENERATED_HDRS ${GENERATED_HDRS} CACHE INTERNAL "Protobuf生成的头文件列表")
    
    message(STATUS "Protobuf: 生成目标 '${PROTOBUF_GENERATED_TARGET}' 已创建")
endfunction()

#####################################################
# 为目标添加protobuf支持
# target_name: 目标名称
# 自动添加protobuf依赖、包含目录和生成文件依赖
#####################################################
function(add_protobuf_to_target target_name)
    if(NOT PROTOBUF_ENABLED)
        return()
    endif()
    
    # 添加protobuf库依赖
    target_link_libraries(${target_name} PRIVATE ${Protobuf_LIBRARIES})
    
    # 添加包含目录
    if(Protobuf_INCLUDE_DIRS)
        target_include_directories(${target_name} PRIVATE ${Protobuf_INCLUDE_DIRS})
    endif()
    
    # 添加生成文件目录
    target_include_directories(${target_name} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
    
    # 添加生成文件依赖
    if(PROTOBUF_GENERATED_TARGET)
        add_dependencies(${target_name} ${PROTOBUF_GENERATED_TARGET})
    endif()
    
    message(STATUS "Protobuf: 已为目标 '${target_name}' 添加protobuf支持")
endfunction()

#####################################################
# 获取protobuf相关的编译选项
# 返回需要添加到COMMON_PRIVATE_DEPS的依赖列表
#####################################################
function(get_protobuf_deps output_var)
    set(deps "")
    if(PROTOBUF_ENABLED AND Protobuf_LIBRARIES)
        list(APPEND deps ${Protobuf_LIBRARIES})
    endif()
    set(${output_var} ${deps} PARENT_SCOPE)
endfunction()

#####################################################
# 获取protobuf相关的包含目录
# 返回需要添加到COMMON_INCLUDE_DIRS的目录列表
#####################################################
function(get_protobuf_include_dirs output_var)
    set(dirs "")
    if(PROTOBUF_ENABLED)
        if(Protobuf_INCLUDE_DIRS)
            list(APPEND dirs ${Protobuf_INCLUDE_DIRS})
        endif()
        list(APPEND dirs ${CMAKE_CURRENT_BINARY_DIR})
    endif()
    set(${output_var} ${dirs} PARENT_SCOPE)
endfunction()

#####################################################
# 检查目标是否需要protobuf支持
# 根据目标名称判断是否为protobuf相关的demo
#####################################################
function(target_needs_protobuf target_name output_var)
    set(needs_protobuf FALSE)
    
    if(PROTOBUF_ENABLED)
        # 检查是否为protobuf相关的目标
        if(target_name MATCHES ".*protobuf.*" OR 
           target_name STREQUAL "demos_real_protobuf_demo" OR
           target_name STREQUAL "demos_protobuf_serializer_test")
            set(needs_protobuf TRUE)
        endif()
    endif()
    
    set(${output_var} ${needs_protobuf} PARENT_SCOPE)
endfunction()
